/**
 * Base unit/ship class
 */
Unit = new Class({
	_type : "Unit",
	Implements : Events,
	id : null,
	
	private : {
		player : null,
		visible : true,
		possibleMoves : new Hash({ 	// relative to current position
			mT_agile : [[-1,-1],[0,-1],[1,-1],[-1,0],[0,0],[1,0],[-1,1],[0,1],[1,1]]
		}),
		/**
		 * Defines how the ship can move
		 * @var int movementType_agile|movementType_heavy
		 */
		movementType : mT_agile
	},
	
	/**
	 * Unit/Ship Element
	 * @var Element
	 */
	element : null,
	
	initialize : function(id,params){
		this.element = new Element('span',{'class':'ship'});
		this.setId(id);
		this.element.store('instance',this);
		this.setParams(params);
	},
	
	setId : function(id){
		this.id = id;
		this.element.set('id','unit_'+id);
	},
	
	/**
	 * @param bool elementId true(default) = return the units element ID string (e.g. fox1), false = return db ID (e.g. fox1)
	 * @return string
	 */
	getId : function(elementId){
		return this.id;
	},
	
	setParams : function(params){
		var params = new Hash(params);
		if(params.has('t') && params.has('typ')){ // Ship Type
			this.element.addClass('t'+params.t+'_'+params.typ);
		}
		if(params.has('r')){ 	// Rotation
			this.setBearing(params.r);
		}
		if(params.has('mt')){ 	// Movement Type
			this.setMovementType(params.mt);
		}
		if(params.has('ap')){	// Action Points
			this.setActionPoints(params.ap);
		}
		if(params.has('p')){	// Player ID
			this.setPlayer(params.p);
		}
	},
	
	/**
	 * Set player id
	 * @var int id
	 */
	setPlayer : function(id){
		this.private.player = (id+'').toInt();
	},
	
	/**
	 * get player id
	 * @return int
	 */
	getPlayer : function(){
		return this.private.player;
	},
	
	/**
	 * Set how many moves a unit can make
	 */
	setActionPoints : function(n){
		this.element.setProperty('ap',n);
		this.element.setProperty('apLeft',n);
	},
	
	setBearing : function(rot){
		this.element.removeClass('rot'+this.getBearing());
		this.element.setProperty('rot',rot);
		this.element.addClass('rot'+rot);
	},
	
	/**
	 * Get ship bearing in degrees (0-315)
	 * @return int
	 */
	getBearing : function(){
		var rot = this.element.getProperty('rot')+'';
		return rot.toInt();
	},
	
	getBearingDesc : function(){
		switch(this.getBearing()){
			case 0: return "North";
			case 45: return "North-East";
			case 315: return "North-West";
			case 90: return "East";
			case 135: return "South-East";
			case 180: return "South";
			case 225: return "South-West";
			case 270: return "West";
		}
	},
	
	/**
	 * Set how ship handles
	 */
	setMovementType : function(type){
		this.private.movementType = type;
	},
	
	getMovementType : function(){
		return this.private.movementType;
	},
	
	getMovementTypeDesc : function(){
		switch(this.private.movementType){
			case mT_agile: return "Light";
			case mT_heavy: return "Heavy";
		}
	},
	
	isSelected : function(){
		return this.element.hasClass('selected');
	},
	
	isVisible : function(){
		return this.element.hasClass('invisible') ? false : true;
	},
	
	setVisible : function(){
		this.element.removeClass('invisible');
	},
	
	setInvisible : function(){
		this.element.addClass('invisible');
	},
	
	/**
	 * Select unit
	 */
	select : function(){
		g = GameEng.getInstance();
		for(var n=0;n<g.map.unitsFlat.length;n++){
			g.map.unitsFlat[n].unselect();
		}
		this.element.addClass('selected');
		g.setSelected(this);
		this._highlightPossibleMoves();
		this.element.store('animSelected',this._selectedAnimation.periodical(250,this));
		g.tileInfo.show(this);
		this.fireEvent('selected');
	},
	
	/**
	 * Select/unselect toggle
	 */
	toggleSelect : function(){
		if(this.isSelected()){
			this.unselect();
		}else{
			this.select();
		}
	},
	
	unselect : function(){
		g = GameEng.getInstance();
		if(this.element.retrieve('animSelected')) $clear(this.element.retrieve('animSelected'));
		this.element.store('animSelected',null);
		this.element.removeClass('selected');
		this.setVisible();
		g.tileInfo.hide();
		g.clearSelected();
		this.fireEvent('unselected');
	},
	
	/**
	 * Translate a move command into new coordinates @todo make all units move backwards when press backwards
	 * @param str move e.g "nw" would be north west
	 * @return Object coordinates+bearing
	 */
	translateMove : function(move){
		var curr = this.getCoordinates();
		var trgtX,trgtY,trgtR;
		
		switch(this.getMovementType()){
		
			case mT_agile:
				switch(move){
					case "n":	trgtX = curr.x;		trgtY = curr.y-1;	trgtR = 0;		break;
					case "ne":	trgtX = curr.x+1;	trgtY = curr.y-1;	trgtR = 45;		break;
					case "e":	trgtX = curr.x+1;	trgtY = curr.y;		trgtR = 90;		break;
					case "se":	trgtX = curr.x+1;	trgtY = curr.y+1;	trgtR = 135;	break;
					case "s":	trgtX = curr.x;		trgtY = curr.y+1;	trgtR = 180;	break;
					case "sw":	trgtX = curr.x-1;	trgtY = curr.y+1;	trgtR = 225;	break;
					case "w":	trgtX = curr.x-1;	trgtY = curr.y;		trgtR = 270;	break;
					case "nw":	trgtX = curr.x-1;	trgtY = curr.y-1;	trgtR = 315;	break;
				}
				break;
				
			case mT_heavy:
				trgtX = curr.x; 
				trgtY = curr.y;
				switch(move){
					case "n":	if(curr.rot==0)  {trgtX = curr.x;	trgtY = curr.y-1;	trgtR = 0;	}else{trgtR=0;	} break;
					case "ne":	if(curr.rot==45) {trgtX = curr.x+1;	trgtY = curr.y-1;	trgtR = 45;	}else{trgtR=45;	} break;
					case "e":	if(curr.rot==90) {trgtX = curr.x+1;	trgtY = curr.y;		trgtR = 90;	}else{trgtR=90;	} break;
					case "se":	if(curr.rot==135){trgtX = curr.x+1;	trgtY = curr.y+1;	trgtR = 135;}else{trgtR=135;} break;
					case "s":	if(curr.rot==180){trgtX = curr.x;	trgtY = curr.y+1;	trgtR = 180;}else{trgtR=180;} break;
					case "sw":	if(curr.rot==225){trgtX = curr.x-1;	trgtY = curr.y+1;	trgtR = 225;}else{trgtR=225;} break;
					case "w":	if(curr.rot==270){trgtX = curr.x-1;	trgtY = curr.y;		trgtR = 270;}else{trgtR=270;} break;
					case "nw":	if(curr.rot==315){trgtX = curr.x-1;	trgtY = curr.y-1;	trgtR = 315;}else{trgtR=315;} break;
				}
				break;
		}
		//console.log("c.x="+curr.x+" c.y="+curr.y+" c.r="+curr.rot+" --> t.x="+trgtX+" t.y="+trgtY+" t.r="+trgtR);
		return {'x':trgtX,'y':trgtY,'rot':trgtR};
	},
	
	/**
	 * Move unit to map coordinates
	 * @param int x
	 * @param int y
	 * @param int rot
	 * @param bool anim [false]
	 * @param bool withPermissions [true]
	 */
	move : function(x,y,rot,anim,withPermissions){
		var g = GameEng.getInstance();
		if(typeof anim !== 'boolean') anim = false;
		if(typeof withPermissions !== 'boolean') withPermissions = true;
		if(withPermissions){
			if(this.getPlayer()!=g.hostPlayer){
				// @todo info select
				return false;
			}
			if(!this.getActionPointsLeft()){
				return false;
			}
		}
		if(g.map.tiles[x][y]){
			this.setVisible(); // attempt to stop unit moving whilst invisible
			this.decrementActionPointsLeft();
			this.setCoordinates(x,y);
			this.setBearing(rot);
			var left = x * g.map.options.tileWidthHeight;
			var top = y * g.map.options.tileWidthHeight;
			if(anim){
				tween = this.element.retrieve('tween');
				if(!tween){
					this.element.store('tween',new Fx.Morph(this,{'link':'chain'}));
					tween = this.element.retrieve('tween');
					var obj = this;
					tween.addEvent('start',function(){
						obj.element.setProperty('moving',1);
					});
					tween.addEvent('complete',function(){
						obj.element.setProperty('moving',0);
					});
				}
				this.element.retrieve('tween').start({'left':left,'top':top});
			}else{
				this.element.setStyles({'left':left+'px','top':top+'px'});
			}
			if(anim) g.tileInfo.update(this);
			return true;
		}
	},
	
	/**
	 * Get number of moves left for unit
	 * @return int
	 */
	getActionPointsLeft : function(){
		return (this.element.getProperty('apLeft')+'').toInt();
	},
	
	decrementActionPointsLeft : function(){
		this.element.setProperty('apLeft',this.getActionPointsLeft()-1);
	},
	
	fire : function(){/*
		var yTrail = $('wpnTrailY');
		var yFx = new Fx.Tween(yTrail,{
			'duration' : 2500,
			'transition' : 'back:in'
		});
		
		var xTrail = $('wpnTrailX');
		var xFx = new Fx.Tween(xTrail,{
			'duration' : 2500,
			'transition' : 'sine:in'
		});
		yFx.set('left',310); // remove
		xFx.set('top',311); // remove
		yFx.start('left',384);
		xFx.start('top',105);
		*/
		var miss = $('wpnMissileTest');
		var yFx = new Fx.Tween(miss,{
			'duration' : 2500,
			'transition' : 'back:in',
				'link' : 'chain'
		});
		var xFx = new Fx.Tween(miss,{
			'duration' : 2500,
			'transition' : 'sine:in',
			'link' : 'chain'
		});
		yFx.set('left',453); // remove
		xFx.set('top',308); // remove
		yFx.start('left',384);
		xFx.start('top',105);
	},
	
	setCoordinates : function(x,y){
		var old = this.getCoordinates();
		var g = GameEng.getInstance();
		this.element.set('x',x);
		this.element.set('y',y);
		if(old.x && old.y){
			oldUnitsArr = g.map.units[old.x][old.y];
			newUnitsArr = new Array();
			for(var n=0;n<oldUnitsArr.length;n++){
				if(oldUnitsArr[n].id!=this.id) newUnitsArr.include(oldUnitsArr[n]);
			}
			g.map.units[old.x][old.y] = newUnitsArr; // remove unit from old position
		}
		g.map.units[x][y].include(this); // add unit to new position
	},
	
	getCoordinates : function(){
		var x = this.element.getProperty('x')+'';
		var y = this.element.getProperty('y')+'';
		var rot = this.element.getProperty('rot')+'';
		return {'x':x.toInt(),'y':y.toInt(),'rot':rot.toInt()};
	},
	
	_highlightPossibleMoves : function(){
		/*var opts = this.private.possibleMoves.get(this.movementType);
		var curr = this.getCoordinates();
		for(var n=0;n<opts.length;n++){
			gameEng.map.tiles[(curr.x+opts[n][0])][(curr.y+opts[n][1])].setAsPossibleMove();
		}*/
	},
	
	/**
	 * Is unit currently being tweened to a new coordinate
	 */
	isMoving : function(){
		return this.element.getProperty('moving')=='1' ? true : false;
	},
	
	_selectedAnimation : function(){
		if(this.isMoving()){
			this.setVisible();
		}else{
			if(this.isVisible()){
				this.setInvisible();
			}else{
				this.setVisible();
			}
		}
	},
	
	toElement : function(){
		return this.element;
	}
});

/* -- Unit Class Static Methods -- */

/**
 * Fetch unit by id
 * @param id string
 * @return Unit
 */
Unit.getUnitById = function(id){
	var g = GameEng.getInstance();
	for(var n=0;n<g.map.unitsFlat.length;n++){
		if(g.map.unitsFlat[n].id==id){
			return g.map.unitsFlat[n];
		}
	}
}